<template>
  <div>
      <!-- 面包屑导航 -->
      <el-breadcrumb separator-class="el-icon-arrow-right">
        <el-breadcrumb-item :to="{ path: '/home' }">首页</el-breadcrumb-item>
        <el-breadcrumb-item>权限管理</el-breadcrumb-item>
        <el-breadcrumb-item>角色列表</el-breadcrumb-item>
      </el-breadcrumb>
      <!-- 卡片视图 -->
      <el-card>
          <el-button type='primary' @click='addDialogVisible=true'>添加角色</el-button>
          <!-- 角色表格 -->
          <el-table :data='rolesList' border stripe>
              <!-- 角色展开行 -->
              <el-table-column type="expand">
                <template slot-scope="scope">
                    <!-- 栅格布局 ,把每一行分成24列-->
                    <!-- 当索引值是0时，加上 bd-top -->
                    <el-row class="v-center" :class="['bd-bottom',index1===0 ? 'bd-top':'']" v-for="(item1,index1) in scope.row.children" :key="item1.id">
                        <!-- 渲染一级权限 -->
                        <el-col :span='5'>
                            <el-tag closable @close='removeRightById(scope.row,item1.id)'>{{item1.authName}}</el-tag>
                            <i class="el-icon-caret-right"></i>
                        </el-col>
                        <!-- 渲染二级权限 -->
                        <el-col :span='19'>
                            <el-row class="v-center" :class="[index2===0 ? '':'bd-top']" v-for="(item2,index2) in item1.children" :key="item2.id">
                                <el-col :span='6'>
                                    <el-tag closable @close='removeRightById(scope.row,item2.id)' type='success'>{{item2.authName}}</el-tag>
                                    <i class="el-icon-caret-right"></i>
                                </el-col>
                                <el-col :span='18'>
                                    <!-- closable表示可移除的标签 -->
                                    <el-tag closable @close='removeRightById(scope.row,item3.id)' type="warning" v-for="(item3) in item2.children" :key="item3.id">
                                        {{item3.authName}}
                                    </el-tag>
                                </el-col>
                            </el-row>
                        </el-col>
                    </el-row>
                </template>
              </el-table-column>
              <el-table-column type='index'></el-table-column>
              <el-table-column label='角色名称' prop='roleName' width="270"></el-table-column>
              <el-table-column label='角色描述' prop='roleDesc' width="270"></el-table-column>
              <el-table-column label='操作'>
                  <template slot-scope="scope">
                    <!-- 修改角色信息按钮 -->
                    <el-button
                    type="primary"
                    icon="el-icon-edit"
                    size="mini"
                    @click='showEditDialog(scope.row.id)'
                    >编辑</el-button>
                    <!-- 删除角色按钮 -->
                    <el-button
                    type="danger"
                    icon="el-icon-delete"
                    size="mini"
                    @click='removeUserById(scope.row.id)'
                    >删除</el-button>
                    <!-- 设置用户角色按钮 -->
                    <el-tooltip
                    effect="dark"
                    content="分配权限"
                    placement="top"
                    :enterable="false"
                    :open-delay='500'
                    >
                    <el-button
                        type="warning"
                        icon="el-icon-setting"
                        size="mini"
                        @click='showSetRightDialog(scope.row)'
                    >分配权限</el-button>
                    </el-tooltip>
                  </template>
              </el-table-column>
          </el-table>
      </el-card>
      <!-- 添加角色对话框 -->
      <el-dialog
        title="请输入要添加的角色"
        :visible.sync="addDialogVisible"
        @close='closeAddDialog'
        width="50%">
        <!-- 添加角色输入框 -->
        <el-form label-width="80px" :model='addForm' :rules='addFormRules' ref='addFormRef'>
            <el-form-item label='角色名称' prop='roleName'>
                <el-input v-model='addForm.roleName'></el-input>
            </el-form-item>
            <el-form-item label='角色描述' prop='roleDesc'>
                <el-input v-model='addForm.roleDesc'></el-input>
            </el-form-item>
        </el-form>
        <span slot="footer" class="dialog-footer">
            <el-button @click="addDialogVisible = false">取 消</el-button>
            <el-button type="primary" @click="addRole">确 定</el-button>
        </span>
      </el-dialog>
      <!-- 修改角色对话框 -->
      <el-dialog
        title="请编辑要修改的角色"
        :visible.sync="editDialogVisible"
        @close='closeEditDialog'
        width="50%">
        <!-- 修改角色输入框 -->
        <el-form label-width="80px" :model='editForm' :rules='editFormRules' ref='editFormRef'>
            <el-form-item label='角色名称' prop='roleName'>
                <el-input v-model='editForm.roleName'></el-input>
            </el-form-item>
            <el-form-item label='角色描述' prop='roleDesc'>
                <el-input v-model='editForm.roleDesc'></el-input>
            </el-form-item>
        </el-form>
        <span slot="footer" class="dialog-footer">
            <el-button @click="editDialogVisible = false">取 消</el-button>
            <el-button type="primary" @click="editRole">确 定</el-button>
        </span>
      </el-dialog>
      <!-- 分配权限对话框 -->
      <el-dialog
        title="权限管理"
        :visible.sync="rightDialogVisible"
        width="50%"
        @close='clearDefKeys'>
        <!-- 树型控件 
        show-checkbox表示是否可选择，
        props表示自定义显示内容格式，
        node-key表示以id值作为唯一标识，
        default-checked-keys表示默认勾选的权限（根据node-key指定的标识）
        default-expand-all是否默认展开所有节点-->
        <el-tree 
        :data="rightslist" 
        :props='treeProps' 
        show-checkbox 
        node-key="id" 
        :default-checked-keys='defKeys' 
        default-expand-all
        ref='allotRightRef'></el-tree>
        <span slot="footer" class="dialog-footer">
            <el-button @click="rightDialogVisible = false">取 消</el-button>
            <el-button type="primary" @click="allotRights">确 定</el-button>
        </span>
      </el-dialog>
  </div>
</template>

<script>
export default {
    name:'Roles',
    data(){
        // 自定义校验规则，角色名称只有空格也不能添加
        var checkRoleName=(rule,value,callback)=>{
            if(value.trim()!=='') return callback()
            // 验证失败返回错误提示
            callback(new Error('角色名称不能全是空格'))
        };
        return{
            // 保存角色列表数据
            rolesList:[],
            // 控制添加角色对话框是否出现
            addDialogVisible:false,
            // 保存添加角色的数据
            addForm:{
                roleName:'',
                roleDesc:''
            },
            // 添加角色的验证规则
            addFormRules:{
                roleName:[
                    {required:true,message:'请输入角色名',trigger:'blur'},
                    {validator:checkRoleName,trigger:'blur'}
                ],
                roleDesc:[
                    {required:true,message:'请输入角色描述',trigger:'blur'}
                ]
            },
            // 控制修改角色对话框是否出现
            editDialogVisible:false,
            // 修改角色数据
            editForm:{},
            // 修改角色校验规则,共用了添加角色的校验规则
            editFormRules:{
                roleName:[
                    {required:true,message:'请输入角色名',trigger:'blur'},
                    {validator:checkRoleName,trigger:'blur'}
                ],
                roleDesc:[
                    {required:true,message:'请输入角色描述',trigger:'blur'}
                ]
            },
            // 控制分配权限对话框是否出现
            rightDialogVisible:false,
            // 保存获取的所有权限 (树型)
            rightslist:[],
            // 树型控件显示格式
            treeProps:{
                // 父子嵌套字段
                children:'children',
                // 指定要显示的树型
                label:'authName'
            },
            // 角色已经拥有的权限id
            defKeys:[],
            // 权限的归属角色id
            roleId:''
        }
    },
    created(){
        this.getRolesList()
    },
    methods:{
        // 获取角色列表
        async getRolesList(){
            const {data:res} = await this.$http.get('roles')
            if(res.meta.status!==200) return this.$message.error('获取角色列表失败')
            this.rolesList=res.data
        },
        // 取消添加角色时，清空之前写入输入框的文字
        closeAddDialog(){
            this.$refs.addFormRef.resetFields()
        },
        // 添加角色预验证
        addRole(){
            this.$refs.addFormRef.validate(async boolean=>{
                if(!boolean) return this.$message.error('预验证未通过，请检查输入是否合法')
                // 发送请求
                const {data:res} = await this.$http.post('roles',this.addForm)
                if(res.meta.status!==201) return this.$message.error('添加角色失败')
            })
            // 重新获取最新的角色数据
            this.getRolesList()
            // 提示信息
            this.$message.success('添加角色成功')
            // 关闭对话框
            this.addDialogVisible = false
        },
        // 修改角色信息，根据 id查询渲染至页面
        async showEditDialog(id){
            // 根据 id查询要修改的角色数据
            const {data:res} = await this.$http.get('roles/'+id)
            if(res.meta.status!==200) return this.$message.error('查询角色信息失败')
            // 将数据保存并渲染
            this.editForm=res.data
            // 关闭修改对话框
            this.editDialogVisible=true
        },
        // 取消修改角色时，清空之前写入输入框的文字
        closeEditDialog(){
            this.$refs.editFormRef.resetFields()
        },
        // 修改角色预验证和提交
        editRole(){
            this.$refs.editFormRef.validate(async boolean=>{
                if(!boolean) return this.$message.error('修改角色预验证失败')
                // 发送请求更新数据
                const {data:res} = await this.$http.put('roles/'+this.editForm.roleId,{roleName:this.editForm.roleName,roleDesc:this.editForm.roleDesc})
                if(res.meta.status!==200) return this.$message.error('修改角色信息提交失败')
                this.$message.success('修改角色信息成功')
                // 更新最新数据
                this.getRolesList()
                // 关闭修改对话框
                this.editDialogVisible=false
            })


            this.editDialogVisible=true
        },
        // 删除角色
        async removeUserById(id){
            const confirmResult = await this.$confirm('此操作将永久删除该角色,是否继续？','提示',{
                confirmButtonText:'确认',
                cancelButtonText:'取消',
                type:'warning'
            }).catch(err=>err)
            if(confirmResult!=='confirm') return this.$message.info('已经取消删除')
            const {data:res} = await this.$http.delete('roles/'+id)
            if(res.meta.status!==200) this.$message.error('删除角色失败')
            this.$message.success('删除角色成功')
            // 重新获取最新的角色列表
            this.getRolesList()
        },
        // 点击关闭权限标签，触发事件 (角色展开行)
        async removeRightById(role,rightId){
            // 弹框提示是否删除
            const confirmResult = await this.$confirm('此操作将永久删除该权限,是否继续？','提示',{
                confirmButtonText:'确认',
                cancelButtonText:'取消',
                type:'warning'
            }).catch(err=>err)
            if(confirmResult!=='confirm') return this.$message.info('已经取消删除')
            // 发送请求删除三级权限
            const {data:res} = await this.$http.delete(`roles/${role.id}/rights/${rightId}`)
            if(res.meta.status!==200) return this.$message.error('移除权限失败')
            // 更新角色列表数据
            // this.getRolesList()
            // 不全部更新页面刷新
            role.children=res.data
            this.$message.success('移除权限成功')
        },
        // 展示分配权限对话框并获取所有权限
        async showSetRightDialog(roles){
            const {data:res} = await this.$http.get('rights/tree')
            if(res.meta.status!==200) return this.$message.error('以树型获取全部权限失败')
            // 保存以树型获取的所有权限
            this.rightslist=res.data

            // 递归获取三级权限的id保存在 defKeys数组中
            this.getLeafKeys(roles,this.defKeys)

            // 将权限对应的角色id保存(提交新权限时使用)
            this.roleId=roles.id

            this.rightDialogVisible=true
        },
        // 以递归的方式获取角色下三级权限的id
        getLeafKeys(node,arr){
            if(!node.children) return arr.push(node.id)
            node.children.forEach(item=>{
                this.getLeafKeys(item,arr)
            })
        },
        // 分配权限对话框关闭时，清空数组 defKys中的 id数据
        clearDefKeys(){
            // this.defKeys.splice(0,this.defKeys.length)
            this.defKeys=[]
        },
        // 向数据库提交最新修改的权限
        async allotRights(){
            // 最新的权限 id
            const keys = [
                ...this.$refs.allotRightRef.getCheckedKeys(),
                ...this.$refs.allotRightRef.getHalfCheckedKeys()
            ]
            const {data:res} = await this.$http.post('roles/'+this.roleId+'/rights',{rids:keys.join(',')})
            if(res.meta.status!==200) return this.$message.error('权限更新失败')

            // 重新获取最新的角色列表
            this.getRolesList()
            this.$message.success('权限更新成功')
            this.rightDialogVisible=false
        }
    }
}
</script>

<style scoped>
    .el-card{
        margin-top: 20px;
        width:95%;
    }
    .el-button{
        margin-bottom: 15px;
    }
    .el-tag{
        margin: 10px;
    }
    .bd-top{
        border-top:1px solid #eee;
    }
    .bd-bottom{
        border-bottom:1px solid #eee;
    }
    /* 纵向居中 */
    .v-center{
        display: flex;
        align-items: center;
    }
</style>